#include "UdpSocket.h"
#include <string.h>

UdpSocket::UdpSocket()
{
	m_Socket=-1;
	isInit=false;
	m_len=sizeof(serverAddr);
	p_tempIP=NULL;
	n_tempPort=0;
}

UdpSocket::~UdpSocket()
{
}

bool UdpSocket::setServer(const char *serverIP, int serverPort)
{
	bool temp=false;
	do
	{
		if (!isInit)
		{
			if (-1 == (m_Socket=socket(AF_INET,SOCK_DGRAM,0)))
			{
				printf("UDP Socket init failed!\n");
				temp= false;
				break;
			}
			if (NULL == serverIP || serverPort<=0 || serverPort>65525 || (0==strcmp("0.0.0.0",serverIP)))
			{
				printf("serverIP or serverPort is error!\n");
				temp= false;
				break;
			}
#ifdef unix
			bzero(&serverAddr,sizeof(serverAddr));
#endif
			serverAddr.sin_family=AF_INET;
			serverAddr.sin_port=htons(serverPort); //set port
			serverAddr.sin_addr.s_addr=inet_addr(serverIP); //set addr

			isInit=true;
			temp= true;
			break;
		}
		else
		{
			printf("error: socket has been set\n");
			temp= false;
			break;
		}
	}while(false);
	return temp;
}

bool UdpSocket::bindPort(int nPort)
{
	bool temp=false;
	do
	{
		if(!isInit)
		{
			if((m_Socket = socket(AF_INET, SOCK_DGRAM,0)) == -1)
			{
				printf("Error: UDP socket init failed.\n");
				temp= false;
				break;
			}

			struct sockaddr_in addrSrv; 
			addrSrv.sin_addr.s_addr =htonl(INADDR_ANY);   
			addrSrv.sin_family=AF_INET;  
			addrSrv.sin_port=htons(nPort);

			int nRet=bind(m_Socket,(struct sockaddr *)&addrSrv,sizeof(struct sockaddr));   
			if(nRet==0)
			{
				isInit = true;
				printf("Open Port:%d Succeed.\n",nPort);
				temp= true;
				break;
			}
			else
			{
				printf("Error: Open Port:%d Failed.\n",nPort);
				temp= false;
				break;
			}
		}
		else
		{
			printf("Error: have bind port before...please initSocket.\n");
			temp= false;
			break;
		}
	}while(false);
	return temp;
}

bool UdpSocket::initSocket()
{
	bool temp=false;
	do
	{
		if (isInit) //
		{
			closeUdpSocket();
			printf("reset m_socket is done.\n");
			temp= true;
			break;
		}
	}while(false);
	return temp;
}


//send data
int  UdpSocket::sendData(const char *buf,int bufLen,const char *serverIP,int serverPort,int nTimeOut)
{
	int ret=0;
	do
	{
		if(NULL==buf || bufLen<=0 || serverPort<0 || nTimeOut<0)
		{
			printf("Error:sendData para is error!\n");
			ret= -2;
			break;
		}
		if (!isInit)
		{
			printf("Error:send socket has not init!\n");
			ret= -3;
			break;
		}

		//block send --client
		if(NULL==serverIP && 0==serverPort && 0==nTimeOut) 
		{
			ret = sendto(m_Socket,buf,bufLen,0,(struct sockaddr*)&serverAddr,sizeof(serverAddr));
			break;
		}
		//block send --server
		else if(NULL!=serverIP && serverPort>0 && 0==nTimeOut)
		{
			struct sockaddr_in addrSrv; 
#ifdef unix
			bzero(&addrSrv,sizeof(addrSrv));
#endif
			addrSrv.sin_addr.s_addr =inet_addr(serverIP);   
			addrSrv.sin_family=AF_INET;  
			addrSrv.sin_port=htons(serverPort);

			ret = sendto(m_Socket,buf,bufLen,0,(struct sockaddr*)&addrSrv,sizeof(addrSrv));
			break;
		}
		//no block send --client's usage
		else if(NULL==serverIP && 0==serverPort && nTimeOut>0) 
		{

#ifdef _WIN32
			int nTvlen=nTimeOut;
#else
			struct timeval nTvlen={nTimeOut/1000,(nTimeOut%1000)*1000}; //windows is int
#endif
			int retOpt=setsockopt(m_Socket,SOL_SOCKET,SO_SNDTIMEO,(const char*)&nTvlen,sizeof(nTvlen));
			if(0 != retOpt)
			{
				fprintf(stderr, "setsockopt ::failed, %s\n", strerror(errno));
			}
			ret = sendto(m_Socket,buf,bufLen,0,(struct sockaddr*)&serverAddr,sizeof(struct sockaddr));   
			break;
		}
		//no block with ip && port --server
		else if(NULL!=serverIP && serverPort>0 && nTimeOut>0)
		{
			struct sockaddr_in addrSrv; 

#ifdef unix
			bzero(&addrSrv,sizeof(addrSrv));
#endif
			addrSrv.sin_addr.s_addr =inet_addr(serverIP);   
			addrSrv.sin_family=AF_INET;  
			addrSrv.sin_port=htons(serverPort);

#ifdef _WIN32
			int nTvlen=nTimeOut;
#else
			struct timeval nTvlen={nTimeOut/1000,(nTimeOut%1000)*1000}; //windows is int
#endif

			int retOpt=setsockopt(m_Socket,SOL_SOCKET,SO_SNDTIMEO,(const char*)&nTvlen,sizeof(nTvlen));
			if(0 != retOpt)
			{
				fprintf(stderr, "setsockopt ::failed, %s\n", strerror(errno));
			}
			ret = sendto(m_Socket,buf,bufLen,0,(struct sockaddr*)&addrSrv,sizeof(struct sockaddr));   
			break;
		}
		else
		{
			printf("Error: sendData unknow para!\n");
			ret= -4;
			break;
		}
	}while(false);
	return ret;
}

// recv data
int  UdpSocket::recvData(char *buf, int bufLen, int nTimeOut)
{
	int ret=0;
	do
	{
		if(NULL==buf || bufLen<=0 || nTimeOut<0)
		{
			printf("Error:sendData para is error!\n");
			ret= -2;
			break;
		}
		if (!isInit)
		{
			printf("Error: recv socket has not init!\n");
			ret= -3;
			break;
		}

		//block recv
		if(0==nTimeOut)
		{
			ret = recvfrom(m_Socket,buf,bufLen,0,(struct sockaddr*)&serverAddr,&m_len);
			p_tempIP=inet_ntoa(serverAddr.sin_addr);
			n_tempPort=ntohs(serverAddr.sin_port);
			break;
		}

		int nTotal=0;
		int	nCount=0;
		char *recv_buff=NULL;
		recv_buff=new char[bufLen+1];
		if(recv_buff == NULL)
		{
			printf("Error:cannot alloc recv_buf\n");
			ret= -4;
			break;
		}

		//no block recv
		if(nTimeOut>0)
		{
			do
			{
				memset(recv_buff,0,sizeof(char)*(bufLen+1));
				nCount=receive((unsigned char *)recv_buff, bufLen,nTimeOut);
				if(nCount>=0)
				{
					memcpy(buf+nTotal,recv_buff,sizeof(char)*bufLen);
					nTotal+=nCount;
				}
			}while(nCount>0);
		}
		delete [] recv_buff;
		recv_buff=NULL;
		ret=nTotal;
	}while(false);
	return ret;
}


//recv no-block
int  UdpSocket::receive(unsigned char *szBuf,int nBufLength,int nTimeOut)
{
	int nRet=0;
	do
	{
		if(NULL==szBuf || nBufLength<=0 || nTimeOut<0)
		{
			printf("Error:recv para is error!\n");
			nRet= -2;
			break;
		}
		if (!isInit)
		{
			printf("Error: recv socket has not init!\n");
			nRet= -3;
			break;
		}

		struct sockaddr_in addrClient;
#ifdef _WIN32
		int nlen=sizeof(struct sockaddr);
		int nTvlen=nTimeOut;
#else
		socklen_t nlen=sizeof(struct sockaddr);
		struct timeval nTvlen={nTimeOut/1000,(nTimeOut%1000)*1000};
#endif

		int retOpt=setsockopt(m_Socket,SOL_SOCKET, SO_RCVTIMEO, (const char*)&nTvlen,sizeof(nTvlen));
		if(0 != retOpt)
		{
			fprintf(stderr, "setsockopt ::failed, %s\n", strerror(errno));
		}
		nRet = recvfrom(m_Socket,(char*)szBuf,nBufLength,0,(struct sockaddr*)&addrClient,&nlen); 
		if(nRet>0)
		{
			printf("Received datagram from: %s\n",inet_ntoa(addrClient.sin_addr));
			p_tempIP = inet_ntoa(addrClient.sin_addr);
			n_tempPort = ntohs(addrClient.sin_port);
		}
	}while(false);
	return nRet;
}


//close
void UdpSocket::closeUdpSocket()
{
#ifdef _WIN32
	closesocket(m_Socket);
#else
	close(m_Socket);
#endif
	isInit=false;
	printf("closeUdpSocket!\n");
}


char* UdpSocket::socketIP()
{
	return p_tempIP;
}

int UdpSocket::socketPort()
{
	return n_tempPort;
}
